// IRGenerator.cpp - IR生成实现
#include "IRGenerator.h"

//varDef : bType Ident  '=' initVal  #initVarDef
//本例子展示一个int类型全局变量声明+初始化（例：int a = 10 ; ）的中间代码生成过程的伪代码
//对变量类型，变量名和变量取值的初始化

//InitVarDefContext *ctx是AST的对应结点
void visitInitVarDef(ASTNode *ctx, SymbolTable *s, Module *m, BasicBlock* bb, bool isGlobal, bool isConst) {
    string type = "int";
    string var_name = "initvar";
    std::variant<int, std::string> data;
    visitChildren(ctx, s, m, type, var_name, data);

    if (s->lookup(var_name) != nullptr) {
        cout << "变量名" << var_name << "重复命名" << endl;
        throw std::invalid_argument("变量名重复命名");
    }

    if (isGlobal) {
        int value;
        if (auto* p = std::get_if<int>(&data)) {
            value = *p;
        } else if (auto* p = std::get_if<std::string>(&data)) {
            string lookup_name = removeRedundantBrackets(*p);
            Symbol* symbol = s->lookup(lookup_name);
            if (symbol == nullptr) {
                cout << "变量名" << lookup_name << "未命名" << endl;
                throw std::invalid_argument("变量名未命名");
            }
            value = symbol->value;
        }
        Type* ir_type = m->get_int32_type();
        GlobalVariable* gv = GlobalVariable::create(var_name, m, ir_type, isConst, ConstantInt::get(value, m));
        s->addSymbol(var_name, VAR, type, value, gv, nullptr, nullptr);
    } else {
        Type* i32_Type = m->get_int32_type();
        // 为局部变量分配内存
        AllocaInst* alloca = AllocaInst::create_alloca(i32_Type, bb);
        Value* initial_value = nullptr;
        int value;

        if (auto* p = std::get_if<int>(&data)) {
            // data 是 int 类型，直接创建常量
            initial_value = ConstantInt::get(*p, m);
            value = *p;
        } else if (auto* p = std::get_if<std::string>(&data)) {
            // data 是 string 类型，加载其他变量的值
            string lookup_name = removeRedundantBrackets(*p);
            Symbol* symbol = s->lookup(lookup_name);
            if (symbol == nullptr) {
                cout << "变量名" << lookup_name << "未命名" << endl;
                throw std::invalid_argument("变量名未命名");
            }
            
            value = symbol->value;
            // 获取目标变量的指针（假设局部变量使用 alloc 字段存储 alloca 指令）
            Value* src_ptr = symbol->alloc; // 需要确保符号表中有此字段
            if (!src_ptr) {
                cout << "变量" << lookup_name << "未正确初始化" << endl;
                throw std::invalid_argument("变量未正确初始化");
            }
            // 加载源变量的值
            LoadInst* loaded_value = LoadInst::create_load(i32_Type, src_ptr, bb);
            initial_value = loaded_value;
        }

        // 将初始值存储到 alloca 分配的内存中
        StoreInst::create_store(initial_value, alloca, bb);
        
        s->addSymbol(var_name, VAR, type, value, alloca, nullptr, nullptr, bb);
    }
    return;
}


void visitChildren(ASTNode *ctx, SymbolTable* s, Module* m, string &type, string &var_name, variant<int, std::string> &data) {

    for(int i=0; i < (int)ctx->children.size(); i++){
        // cout << "ctx->children[i]->type : " << ctx->children[i]->type << endl;
        //访问initVarDef子结点
        if(ctx->children[i]->type == "argVarDecl"){
            if(ctx->children[i]->value == "argVarDecl"){
                // 此时argVarDecl还有子节点
                visitInitVarDef(ctx->children[i], s, m);
            }
        }

    }

    for(int i=0; i < (int)ctx->children.size(); i++){
        //children.size()得到ctx节点的子节点数
        //访问bType子结点获取变量类型
        // cout << "ctx->children[i]->type : " << ctx->children[i]->type << endl;
        if(ctx->children[i]->type == "bType"){
            // cout << "Hello bType" << endl;
            visitBType(ctx->children[i], type);
        }
        //访问valDef子结点获取变量名和初始数值
        else if(ctx->children[i]->type == "varDef"){
            ASTNode *child = ctx->children[i];
            for(int j=0; j < (int)child->children.size(); j++){
                if(child->children[j]->type == "Ident"){
                    visitIdent(child->children[j], var_name);
                } else if(child->children[j]->type == "argVarDef"){
                    ASTNode *argChild = child->children[j];
                    for(int k=0; k < (int)argChild->children.size(); k++){
                        if(argChild->children[k]->type == "initVal"){
                            visitNumber(argChild->children[k], data);
                        }
                    }
                }
            }
        }
    }


    return;
}

void visitBType(ASTNode *ctx, string &type) {
    //根据bType的类型来设置变量类型
    type = ctx->value;
    // cout << "修改后变量类型为" << type << endl;
}
void visitIdent(ASTNode *ctx, string &var_name) {
    var_name = ctx->value;
    // cout << "修改后变量名为" << var_name << endl;
}
void visitNumber(ASTNode *ctx, variant<int, std::string> &data) {
    if(isInteger(ctx->value)) {
        data = stoi(ctx->value);
        return;
    }
    else{
        data = ctx->value;
    }
    // cout << "修改后变量初始值为" << data << endl;
}



void visitFuncDef(ASTNode *ctx, SymbolTable *s, Module *m) {
    // 处理函数定义
    string funcName = ctx->children[1]->value;
    string funcType = ctx->children[0]->value;
    // pair.first是参数类型，pair.second是参数名
    vector<pair<string, string>> paramNames;

    process_funcFParams(ctx->children[3], paramNames);

    Type* ret_type = m -> get_void_type();
    vector<Type*> param_types;
    for (auto paramName : paramNames) {
        Type* param_type = m -> get_int32_type(); // 假设参数类型为int
        param_types.push_back(param_type);
    }

    FunctionType* func = FunctionType::get(ret_type, param_types);

    // 创建函数
    Function* function = Function::create(func, funcName, m);
    s->addSymbol(funcName, FUNC, funcType, 0, NULL, NULL, function);

    // 处理函数体
    for (auto child : ctx->children) {
        if (child->type == "block") {
            visitBlock(child, s, m, function, funcName);
        }
    }
}

void AST_NodeTraversal_IRGenerate(ASTNode* node, SymbolTable* s, Module* m, BasicBlock* bb) {
    // 前序遍历
    if (!node) return;
    // 处理当前节点
    if(node->type == "varDecl"){
        visitInitVarDef(node, s, m, bb, false, false);
        return;
    }
    else if(node->type == "assignExp"){
        visitAssignExp(node, s, m, bb);
        return;
    }
    else if(node->type == "funcDef"){
        visitFuncDef(node, s, m);
        return;
    }

    for (auto child : node->children) {
        AST_NodeTraversal_IRGenerate(child, s, m, bb);
    }
}

void visitBlock(ASTNode *ctx, SymbolTable *s, Module *m, Function* f, string f_name) {
    s -> enterScope();
    BasicBlock *bb = BasicBlock::create(m, f_name + "_ENTRY", f);
    // f -> add_basic_block(bb);

    // 处理块中的语句
    AST_NodeTraversal_IRGenerate(ctx, s, m, bb);


    s -> exitScope();
    // f -> remove(bb);
    return;
}